package com.crm.miaohe.service;

import com.crm.miaohe.common.ApplicationConstant;
import com.crm.miaohe.controller.PageResponse;
import com.crm.miaohe.controller.authentication.request.user.AuthUserQueryRequest;
import com.crm.miaohe.controller.authentication.request.user.AuthUserRequest;
import com.crm.miaohe.controller.authentication.response.user.AuthUserDetail;
import com.crm.miaohe.controller.authentication.response.user.AuthUserOverview;
import com.crm.miaohe.exception.ErpBusinessException;
import com.crm.miaohe.mapper.TblAuthUserMapper;
import com.crm.miaohe.model.TblAuthUser;
import com.crm.miaohe.model.TblAuthUserExample;
import com.crm.miaohe.security.Role;
import com.crm.miaohe.utils.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

@Slf4j
@Service
public class AuthUserServiceImpl implements AuthUserService {
    private final TblAuthUserMapper authUserMapper;
    private final PasswordEncoder passwordEncoder;

    public AuthUserServiceImpl(TblAuthUserMapper authUserMapper,
                               PasswordEncoder passwordEncoder) {
        this.authUserMapper = authUserMapper;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public void addAuthUser(AuthUserRequest params) {
        // 判断两次输入密码是否相同
        String password = params.getPassword();
        if (!password.equals(params.getPasswordConfirm())) {
            log.error("Password and PasswordConfirm are different. password: {}; passwordConfirm: {}",
                    password, params.getPasswordConfirm());
            throw new ErpBusinessException(HttpStatus.BAD_REQUEST,
                    new IllegalArgumentException("Password and PasswordConfirm have to be same."),
                    ApplicationConstant.CUS001,
                    params.getPassword(), params.getPasswordConfirm());
        }
        // 判断当前电话号码是否被注册过
        TblAuthUserExample example = new TblAuthUserExample();
        example.createCriteria().andPhoneNumberEqualTo(params.getPhoneNumber()).andDeletedEqualTo(false);
        long count = authUserMapper.countByExample(example);
        if (count > 0) {
            throw new ErpBusinessException(HttpStatus.BAD_REQUEST, "Auth002", params.getPhoneNumber());
        }
        TblAuthUser authUser = new TblAuthUser();
        authUser.setDeleted(false);
        authUser.setLoginLocked(false);
        authUser.setAccountLocked(false);
        BeanUtils.copyProperties(params, authUser);
        authUser.setPassword(passwordEncoder.encode(params.getPassword()));
        authUserMapper.insert(authUser);
    }

    @Override
    public PageResponse<AuthUserOverview> queryUsers(AuthUserQueryRequest request) {
        TblAuthUserExample authUserExample = new TblAuthUserExample();
        TblAuthUserExample.Criteria criteria = authUserExample.createCriteria();
        if (!ObjectUtils.isEmpty(request.getPhoneNumber())) {
            criteria.andPhoneNumberEqualTo(request.getPhoneNumber());
        }
        if (!ObjectUtils.isEmpty(request.getUsername())) {
            criteria.andUsernameLike(StringUtils.quoteWith(request.getUsername(), "%"));
        }

        criteria.andDeletedIsNotNull().andDeletedNotEqualTo(true);
        PageInfo<AuthUserOverview> pageInfo =
                PageHelper.startPage(request.getPageNo(), request.getPageSize(), "tau.create_time")
                        .doSelectPageInfo(() -> authUserMapper.selectByExample(authUserExample));
        return com.crm.miaohe.controller.PageResponse.<AuthUserOverview>builder()
                .currentPage(pageInfo.getPageNum())
                .totalPage(pageInfo.getPages())
                .totalElement(pageInfo.getTotal())
                .records(pageInfo.getList())
                .build();
    }

    @Override
    public AuthUserDetail currentUser(String username) {
        TblAuthUserExample example = new TblAuthUserExample();
        example.createCriteria().andPhoneNumberEqualTo(username).andDeletedEqualTo(false);
        example.or().andUsernameEqualTo(username).andDeletedEqualTo(false);
        TblAuthUser authUser = authUserMapper.selectByExample(example)
                .stream().findAny().orElseThrow(() -> new UsernameNotFoundException(ApplicationConstant.USERNAME_NOT_FOUND));

        AuthUserDetail resp = new AuthUserDetail();
        resp.setId(authUser.getId());
        resp.setUsername(authUser.getUsername());
        resp.setPhoneNumber(authUser.getPhoneNumber());

        Role role = Role.fromId(authUser.getRoleId());
        resp.setRoleName(role.getAuthority());
        return resp;
    }

    @Override
    public void updatePassword(AuthUserRequest authUserRequest) {
        TblAuthUser tblAuthUser = new TblAuthUser();
        tblAuthUser.setPassword(passwordEncoder.encode(authUserRequest.getPassword()));
        tblAuthUser.setId(authUserRequest.getId());
        authUserMapper.updateByPrimaryKeySelective(tblAuthUser);
    }

    @Override
    public void updateLocked(Long id) {
        TblAuthUser tblAuthUser = new TblAuthUser();
        tblAuthUser.setLoginFailedCount(0);
        tblAuthUser.setAccountLocked(false);
        tblAuthUser.setId(id);
        authUserMapper.updateByPrimaryKeySelective(tblAuthUser);
    }

    @Override
    public void deleteAuthUser(Long id) {
        TblAuthUser tblAuthUser = new TblAuthUser();
        tblAuthUser.setDeleted(true);
        tblAuthUser.setId(id);
        authUserMapper.updateByPrimaryKeySelective(tblAuthUser);
    }

    @Override
    public boolean checkPhoneNumber(AuthUserRequest authUserRequest) {
        TblAuthUserExample example = new TblAuthUserExample();
        example.createCriteria().andIdNotEqualTo(authUserRequest.getId()).andPhoneNumberEqualTo(authUserRequest.getPhoneNumber()).andDeletedEqualTo(false);
        return false;
    }
}
